package com.fengyuncx.tp.ali_log;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.text.TextUtils;

import com.aliyun.sls.android.producer.Log;
import com.aliyun.sls.android.producer.LogProducerCallback;
import com.aliyun.sls.android.producer.LogProducerClient;
import com.aliyun.sls.android.producer.LogProducerConfig;
import com.aliyun.sls.android.producer.LogProducerException;
import com.aliyun.sls.android.producer.LogProducerResult;
import com.fengyuncx.tp.ali_log.utils.DartError;
import com.fengyuncx.tp.ali_log.utils.Dlog;

public class AliLogManager {
    private static AliLogConfig configData;

    public static boolean isLogOpen() {
        return logOpen;
    }

    public static void setLogOpen(boolean logOpen) {
        AliLogManager.logOpen = logOpen;
    }

    private static boolean logOpen = false;
    private static final String TAG = AliLogManager.class.getSimpleName();

    private static AliLogManager sAliLogManager;


    private Context mContext;
    LogProducerClient logClientRequestFailed;
    LogProducerClient logClientCrash;
    LogProducerClient logClientDartError;
//    private LOGClient logClient;
    private AliLogManager(AliLogConfig config){
        mContext = config.context;
    }

    /**
     * @param config 配置数据
     * @return
     */
    public static AliLogManager init(AliLogConfig config){
        AliLogManager.configData = config;
        if(sAliLogManager == null) {
            synchronized (AliLogManager.class){
                if(sAliLogManager == null){
                    sAliLogManager = new AliLogManager(config);
                }
            }
        }
        return sAliLogManager;
    }

    public static void setUUid(String uuid){
        if(configData != null){
            configData.uuid = uuid;
        }
    }

    public static void setUserId(String userId) {
        if(configData != null){
            configData.userId = userId;
        }
    }

    public static void postDartError(String error, String stack) {
        if(sAliLogManager != null){
            DartError dartError = new DartError(error, stack);
            sAliLogManager.putDartErrorLog(dartError);

        }
    }

    public static void postHttpLog(String url, String paramsJson, String responseJson) {
        Dlog.e(TAG, "postHttpLog - sAliLogManager:"+sAliLogManager);
        if(sAliLogManager != null){
            sAliLogManager.putHttpLog(url, paramsJson, responseJson);
        }
    }

    private void init() throws LogProducerException {
//        SLSDatabaseManager.getInstance().setupDB(mContext);
        //        移动端是不安全环境，不建议直接使用阿里云主账号ak，sk的方式。建议使用STS方式。具体参见
//        https://help.aliyun.com/document_detail/62681.html
//        注意：SDK 提供的 PlainTextAKSKCredentialProvider 只建议在测试环境或者用户可以保证阿里云主账号AK，SK安全的前提下使用。
//		  具体使用如下

//        主账户使用方式

//        String AK = config.AK;
//        String SK = config.SK;
//        PlainTextAKSKCredentialProvider credentialProvider =
//                new PlainTextAKSKCredentialProvider(AK, SK);
//        STS使用方式
//        String STS_AK = "******";
//        String STS_SK = "******";
//        String STS_TOKEN = "******";
//        StsTokenCredentialProvider credentialProvider =
//                new StsTokenCredentialProvider(STS_AK, STS_SK, STS_TOKEN);

//        LogProducerConfig conf = getDefaultConfig();
//        //        ClientConfiguration conf = new ClientConfiguration();
//        logClientRequestFailed = new LogProducerClient(conf, new LogProducerCallback() {
//            @Override
//            public void onCall(int resultCode, String reqId, String errorMessage, int logBytes, int compressedBytes) {
//                // 回调
//                // resultCode       返回结果代码
//                // reqId            请求id
//                // errorMessage     错误信息，没有为null
//                // logBytes         日志大小
//                // compressedBytes  压缩后日志大小
//                android.util.Log.d("LogProducerCallback",String.format("%s %s %s %s %s",
//                        LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes));
//            }
//        });

//        conf.setConnectionTimeout(15 * 1000); // 连接超时，默认15秒
//        conf.setSocketTimeout(15 * 1000); // socket超时，默认15秒
//        conf.setMaxConcurrentRequest(5); // 最大并发请求书，默认5个
//        conf.setMaxErrorRetry(2); // 失败后最大重试次数，默认2次
//        conf.setCachable(true);
//        conf.setConnectType(ClientConfiguration.NetworkPolicy.WWAN_OR_WIFI);
//        SLSLog.enableLog(); // log打印在控制台
//        logClient = new LOGClient(mContext, config.endpoint, credentialProvider, conf);

    }


    private LogProducerConfig getDefaultConfig() {
        try {
            LogProducerConfig conf = new LogProducerConfig(mContext, configData.endpoint, configData.project, configData.logStore);
            conf.setAccessKeyId(configData.AK);
            conf.setAccessKeySecret(configData.SK);
            conf.setConnectTimeoutSec(15 * 1000);
            // 每个缓存的日志包的大小上限，取值为1~5242880，单位为字节。默认为1024 * 1024
            conf.setPacketLogBytes(1024 * 1024);
            // 每个缓存的日志包中包含日志数量的最大值，取值为1~4096，默认为1024
            conf.setPacketLogCount(1024);
            // 被缓存日志的发送超时时间，如果缓存超时，则会被立即发送，单位为毫秒，默认为3000
            conf.setPacketTimeout(3000);
            // 单个Producer Client实例可以使用的内存的上限，超出缓存时add_log接口会立即返回失败
            // 默认为64 * 1024 * 1024
            conf.setMaxBufferLimit(64 * 1024 * 1024);
            // 发送线程数，默认为1
            conf.setSendThreadCount(1);

            // 1 开启断点续传功能， 0 关闭
            // 每次发送前会把日志保存到本地的binlog文件，只有发送成功才会删除，保证日志上传At Least Once
            conf.setPersistent(0);
            // 持久化的文件名，需要保证文件所在的文件夹已创建。配置多个客户端时，不应设置相同文件
            conf.setPersistentFilePath(mContext.getFilesDir() + "/log.dat");
            // 是否每次AddLog强制刷新，高可靠性场景建议打开
            conf.setPersistentForceFlush(1);
            // 持久化文件滚动个数，建议设置成10。
            conf.setPersistentMaxFileCount(10);
            // 每个持久化文件的大小，建议设置成1-10M
            conf.setPersistentMaxFileSize(1024 * 1024);
            // 本地最多缓存的日志数，不建议超过1M，通常设置为65536即可
            conf.setPersistentMaxLogCount(65536);
            return conf;
        }catch (LogProducerException e){
            Dlog.e(TAG, e.getMessage());
        }
        return null;
    }

    private void putHttpLog(String url, String paramsJson, String responseJson){
        Dlog.e(TAG, "putHttpLog -url:"+url);
        final Log log = new Log();
        try {
            putPhoneInfo(log);
        }catch (PackageManager.NameNotFoundException e){
            e.printStackTrace();
        }
        log.putContent("url", url);
        log.putContent("params", paramsJson);
        log.putContent("response", responseJson);
        if(logClientRequestFailed == null) {
            final LogProducerConfig config = getDefaultConfig();
            if (config != null) {
                config.setTopic("Request_Failed");
                config.setSource("android");
                /* 创建logGroup */
                try {
                    logClientRequestFailed = new LogProducerClient(config, new LogProducerCallback() {
                        @Override
                        public void onCall(int resultCode, String reqId, String errorMessage, int logBytes, int compressedBytes) {
                            // 回调
                            // resultCode       返回结果代码
                            // reqId            请求id
                            // errorMessage     错误信息，没有为null
                            // logBytes         日志大小
                            // compressedBytes  压缩后日志大小
                            android.util.Log.d("LogProducerCallback", String.format("%s %s %s %s %s",
                                    LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes));
                        }
                    });
                } catch (LogProducerException e) {
                    e.printStackTrace();
                }

            }
        }
        logClientRequestFailed.addLog(log);
    }

    public void putDartErrorLog(Throwable er){

        if(logClientDartError == null) {
            final LogProducerConfig  configCrash = getDefaultConfig();
            if (configCrash != null) {
                configCrash.setTopic("dartError");
                configCrash.setSource("dart");
                /* 创建logGroup */
                try {
                    logClientDartError = new LogProducerClient(configCrash, new LogProducerCallback() {
                        @Override
                        public void onCall(int resultCode, String reqId, String errorMessage, int logBytes, int compressedBytes) {
                            // 回调
                            // resultCode       返回结果代码
                            // reqId            请求id
                            // errorMessage     错误信息，没有为null
                            // logBytes         日志大小
                            // compressedBytes  压缩后日志大小
                            android.util.Log.d("LogProducerCallback", String.format("%s %s %s %s %s",
                                    LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes));
                        }
                    });
                } catch (LogProducerException e) {
                    e.printStackTrace();
                }

            }
        }
        Log errorLog = getErrorLog(er);
        logClientDartError.addLog(errorLog);

    }
    public void putErrorLog(Throwable er){

        if(logClientCrash == null) {
            final LogProducerConfig  configCrash = getDefaultConfig();
            if (configCrash != null) {
                configCrash.setTopic("crash_log");
                configCrash.setSource("android");
                /* 创建logGroup */
                try {
                    logClientCrash = new LogProducerClient(configCrash, new LogProducerCallback() {
                        @Override
                        public void onCall(int resultCode, String reqId, String errorMessage, int logBytes, int compressedBytes) {
                            // 回调
                            // resultCode       返回结果代码
                            // reqId            请求id
                            // errorMessage     错误信息，没有为null
                            // logBytes         日志大小
                            // compressedBytes  压缩后日志大小
                            android.util.Log.d("LogProducerCallback", String.format("%s %s %s %s %s",
                                    LogProducerResult.fromInt(resultCode), reqId, errorMessage, logBytes, compressedBytes));
                        }
                    });
                } catch (LogProducerException e) {
                    e.printStackTrace();
                }

            }
        }
        Log errorLog = getErrorLog(er);
        logClientCrash.addLog(errorLog);

    }

    private Log getErrorLog(Throwable er){
        Dlog.d(TAG, "putErrorLog");
        final Log log = new Log();
        try {
            putPhoneInfo(log);
        }catch (PackageManager.NameNotFoundException e){
            e.printStackTrace();
        }
        log.putContent("error", er.getClass().getName()+":"+er.getMessage());er.printStackTrace();
        StackTraceElement[] stackTraceElements = er.getStackTrace();
        if(stackTraceElements != null && stackTraceElements.length > 0){
            StringBuilder sb = new StringBuilder();
            for(int i=0; i<stackTraceElements.length; i++){
                if(i != 0){
                    sb.append("\n");
                }
                sb.append("#");
                sb.append(i);
                sb.append("\t");
                sb.append(stackTraceElements[i].toString());
            }
            log.putContent("stack_trace", sb.toString());
        }
        return log;
    }

    private void putPhoneInfo(Log log) throws PackageManager.NameNotFoundException {
        if(configData.uuid != null && !configData.uuid.isEmpty()){
            log.putContent("deviceId", configData.uuid);
        }
        if(configData.apiEnv != null && !configData.apiEnv.isEmpty()) {
//            log.putContent("api_env", com.fengyuncx.fycommon.BuildConfig.API_ENV);
            log.putContent("api_env", configData.apiEnv);
        }
        if(configData.terminal != null && !configData.terminal.isEmpty()){
            log.putContent("terminal", configData.terminal);
        }
        if(configData.userId != null && !configData.userId.isEmpty()) {
            log.putContent("userId", configData.userId);
        }
        //得到包管理器
        PackageManager pm = mContext.getPackageManager();
        //得到包对象
        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
        //APP版本号
        log.putContent("app_version", pi.versionName+"_"+pi.versionCode);
        //写入 Android 版本号
        log.putContent("os_version", Build.VERSION.RELEASE+"_"+ Build.VERSION.SDK_INT);
        //手机制造商
        log.putContent("vendor", Build.MANUFACTURER);
        //手机型号
        log.putContent("model", Build.MODEL);
        //CPU架构
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            StringBuilder stringBuilder = new StringBuilder();
            for(int i = 0; i< Build.SUPPORTED_ABIS.length; i++){
                if(TextUtils.isEmpty(Build.SUPPORTED_ABIS[i])){
                    continue;
                }
                if(i != 0){
                    stringBuilder.append(",");
                }
                stringBuilder.append(Build.SUPPORTED_ABIS[i]);
            }
            log.putContent("cpu_abi", stringBuilder.toString());
        }else {
            log.putContent("cpu_abi", Build.CPU_ABI);
        }
    }

//    private void putLog(LogGroup logGroup){
//        Dlog.e(TAG, "putLog logGroup:"+logGroup.LogGroupToJsonString());
//        Dlog.e(TAG, "putLog config:"+config);
//        if(config == null){
//            return;
//        }
//        try {
//            PostLogRequest request = new PostLogRequest(config.project, config.logStore, logGroup);
//            logClientRequestFailed.asyncPostLog(request, new CompletedCallback<PostLogRequest, PostLogResult>() {
//                @Override
//                public void onSuccess(PostLogRequest request, PostLogResult result) {
//                    Dlog.e(TAG, "---onSuccess-request:"+request+", result:"+result);
//                }
//
//                @Override
//                public void onFailure(PostLogRequest request, LogException exception) {
//                    Dlog.e(TAG, "---onFailure-request_logContentType:"+request+", mLogStoreName:"+request.mLogStoreName);
//                    Dlog.e(TAG, "---onFailure-errorCode:"+exception.getErrorCode()+", errorMsg:"+exception.getErrorMessage()+", requestId:"+exception.getRequestId());
////                    System.gc();
//                }
//            });
//        } catch (LogException e) {
//            Dlog.e(TAG, "--LogException:"+e.getErrorMessage());
////            e.printStackTrace();
//        }
//    }


}
